package com.kevin.controller.controller.system;

import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.kevin.common.api.PageDTO;
import com.kevin.common.api.R;
import com.kevin.common.exception.BusinessException;
import com.kevin.service.entity.ScheduleJob;
import com.kevin.service.query.ScheduleJobQuery;
import com.kevin.service.service.ScheduleJobService;
import com.kevin.service.util.job.CronUtils;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.List;

/**
 * 定时任务
 *
 * @author 阿沐 babamu@126.com
 */
@RestController
@RequestMapping("schedule")
@Api(tags = "定时任务")
@AllArgsConstructor
public class ScheduleJobController {
    private final ScheduleJobService scheduleJobService;

    @GetMapping("page")
    @ApiOperation(value = "分页")
    @SaCheckPermission(value = "schedule:page")
    public R<PageInfo<ScheduleJob>> page(PageDTO pageDTO, ScheduleJobQuery query) {
        PageHelper.startPage(pageDTO.getPageNum(), pageDTO.getPageSize());
        return R.ok(new PageInfo<>(scheduleJobService.list(Wrappers.lambdaUpdate(ScheduleJob.class)
                .like(StrUtil.isNotBlank(query.getJobName()), ScheduleJob::getJobName, query.getJobName())
                .like(StrUtil.isNotBlank(query.getJobGroup()), ScheduleJob::getJobGroup, query.getJobGroup())
                .eq(query.getStatus() != null, ScheduleJob::getStatus, query.getStatus()))));
    }

    @GetMapping("{id}")
    @ApiOperation(value = "信息")
    @SaCheckPermission(value = "schedule:info")
    public R<ScheduleJob> get(@PathVariable("id") Long id) {
        return R.ok(scheduleJobService.getById(id));
    }

    @PostMapping
    @ApiOperation(value = "保存")
    @SaCheckPermission(value = "schedule:save")
    public R<String> save(@RequestBody ScheduleJob vo) {
        if (!CronUtils.isValid(vo.getCronExpression())) {
            return R.failed("操作失败，Cron表达式不正确");
        }

        // 检查Bean的合法性
        checkBean(vo.getBeanName());

        scheduleJobService.saveP(vo);

        return R.ok();
    }

    @PutMapping
    @ApiOperation(value = "修改")
    @SaCheckPermission(value = "schedule:update")
    public R<String> update(@RequestBody @Valid ScheduleJob vo) {
        if (!CronUtils.isValid(vo.getCronExpression())) {
            return R.failed("操作失败，Cron表达式不正确");
        }

        // 检查Bean的合法性
        checkBean(vo.getBeanName());

        scheduleJobService.update(vo);

        return R.ok();
    }

    @DeleteMapping
    @ApiOperation(value = "删除")
    @SaCheckPermission(value = "schedule:delete")
    public R<String> delete(@RequestBody List<Long> idList) {
        scheduleJobService.delete(idList);

        return R.ok();
    }

    @PutMapping("run")
    @ApiOperation(value = "立即执行")
    @SaCheckPermission(value = "schedule:run")
    public R<String> run(@RequestBody ScheduleJob vo) {
        scheduleJobService.run(vo);

        return R.ok();
    }

    @PutMapping("change-status")
    @ApiOperation(value = "修改状态")
    @SaCheckPermission(value = "schedule:update")
    public R<String> changeStatus(@RequestBody ScheduleJob vo) {
        scheduleJobService.changeStatus(vo);

        return R.ok();
    }

    private void checkBean(String beanName) {
        // 为避免执行jdbcTemplate等类，只允许添加有@Service注解的Bean
        String[] serviceBeans = SpringUtil.getApplicationContext().getBeanNamesForAnnotation(Service.class);
        if (!ArrayUtil.contains(serviceBeans, beanName)) {
            throw new BusinessException("只允许添加有@Service注解的Bean！");
        }
    }
}
